package com.zx.zxapithirdpart.listener;

import com.rabbitmq.client.Channel;

import com.tencentcloudapi.sms.v20210111.models.SendSmsResponse;
import com.tencentcloudapi.sms.v20210111.models.SendStatus;
import com.zx.zxapicommon.constant.RabbitmqConstant;
import com.zx.zxapicommon.constant.RedisConstant;
import com.zx.zxapicommon.model.dto.SmsDTO;
import com.zx.zxapithirdpart.tencent.SendSmsUtils;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
import org.springframework.amqp.core.Message;
import org.springframework.amqp.rabbit.annotation.RabbitListener;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.RedisTemplate;

import org.springframework.stereotype.Component;

import javax.annotation.Resource;
import java.io.IOException;

/**
 * mq消费者
 * 通过第三方平台发送短信验证码
 * @author zx
 */
@Component
@Slf4j
public class SendSmsListener {

    @Autowired
    private RedisTemplate redisTemplate;

    @Resource
    private SendSmsUtils sendSmsUtils;

    /*
     *
     * 监听发送短信普通队列
     *
     * @param smsDTO
     * @param message
     * @param channel
     */
    @RabbitListener(queues = RabbitmqConstant.SMS_QUEUE_NAME)
    public void sendSmsListener(SmsDTO smsDTO, Message message, Channel channel) throws IOException {
        String messageId = message.getMessageProperties().getMessageId();
        long deliveryTag = message.getMessageProperties().getDeliveryTag();
        //从redis中获取重试次数retryCount
        int retryCount = (int) redisTemplate.opsForHash().get(RedisConstant.SMS_MESSAGE_PREFIX + messageId, "retryCount");

        //如果retryCount大于3，将信息放到死信队列中
        if (retryCount > 3) {
            log.error("短信消息重试超过3次：{}", messageId);

            //basicReject方法拒绝deliveryTag对应的消息，第二个参数是否requeue，true则重新入队列，否则丢弃或者进入死信队列。
            //该方法reject后，该消费者还是会消费到该条被reject的消息。
            channel.basicReject(deliveryTag, false);
            redisTemplate.delete(RedisConstant.SMS_MESSAGE_PREFIX + messageId);
            return;
        }

        try {
            //消费mq发来的消息
            String phoneNum = smsDTO.getPhoneNum();
            String code = smsDTO.getCode();
            if (StringUtils.isAnyBlank(phoneNum, code)) {
                throw new RuntimeException("mq中发来的消息为空");
            }

            //通过第三方平台发送消息
            SendSmsResponse response = null;
            response = sendSmsUtils.sendSmsResponse(phoneNum, code);
            SendStatus[] sendStatusSet = response.getSendStatusSet();
            SendStatus sendStatus = sendStatusSet[0];
            String statusCode = sendStatus.getCode();
            String res = sendStatus.getMessage();
            if(!"OK".equals(statusCode) || "send success".equals(res)){
                throw new RuntimeException("发送验证码失败");
            }

            //手动确认消息,第二个参数为：是否批量.true:将一次性ack(确认)所有小于deliveryTag的消息。
            channel.basicAck(deliveryTag, false);
            log.info("短信发送成功：{}", smsDTO);
            //删除短信相关缓存
            redisTemplate.delete(RedisConstant.SMS_MESSAGE_PREFIX + messageId);
        } catch (Exception e) {
            //发生异常，重试次数+1
            redisTemplate.opsForHash().put(RedisConstant.SMS_MESSAGE_PREFIX + messageId, "retryCount", retryCount + 1);
            //将短信放回队列中重新消费
            channel.basicReject(message.getMessageProperties().getDeliveryTag(), true);
        }

    }


    /*
     *
     * 监听发送短信死信队列
     *
     * @param smsDTO
     * @param message
     * @param channel
     */
    @RabbitListener(queues = RabbitmqConstant.SMS_DELAY_QUEUE_NAME)
    public void smsDelayQueueListener(SmsDTO smsDTO, Message message, Channel channel) throws IOException {
        long deliveryTag = message.getMessageProperties().getDeliveryTag();
        try {
            log.error("监听到死信队列消息==》{}",smsDTO);
            channel.basicAck(deliveryTag,false);
        } catch (Exception e) {
           channel.basicReject(deliveryTag,true);
        }

    }
}
